﻿using Google.Protobuf.WellKnownTypes;
using System.IO.Compression;
using System.Text.Json;

namespace Elio.Sessions;

public class RequestsSession : BaseSession
{
    protected override string SessionName => base.SessionName = "Requests";

    protected override async Task OnReceive(string name, long sessionId, long futureId, params Any[] argv)
    {
        switch (name)
        {
            case "get":
                await Get(sessionId, futureId, argv);
                break;

            case "post":
                await Post(sessionId, futureId, argv);
                break;

            default:
                await base.OnReceive(name, sessionId, futureId, argv);
                break;
        }
    }
    private async Task Get(long sid, long fid, params Any[] argv)
    {
        using HttpClient client = new();
        client.AddHeaders(argv[1].P2String());
        HttpResponseMessage rsp = await client.GetAsync(argv[0].P2String());
        await StartRequest(rsp, sid, fid);
    }

    private async Task Post(long sid, long fid, params Any[] argv)
    {
        using HttpClient client = new();
        client.AddHeaders(argv[1].P2String());
        HttpContent content = new StringContent(argv[2].P2String());
        content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
        HttpResponseMessage rsp = await client.PostAsync(argv[0].P2String(), content);
        await StartRequest(rsp, sid, fid);
    }

    private async Task StartRequest(HttpResponseMessage rsp, long sid, long fid)
    {
        int stateCode = 404;
        string headers = "{}";
        byte[] body = Array.Empty<byte>();

        if (rsp.IsSuccessStatusCode)
        {
            stateCode = 200;
            headers = rsp.GetHeaders();
            Stream rspStream = await rsp.Content.ReadAsStreamAsync();
            using MemoryStream memStream = new();
            GZipStream zipStream = new(memStream, CompressionMode.Compress);
            await rspStream.CopyToAsync(zipStream);
            zipStream.Close();
            body = memStream.ToArray();
        }

        await SendAction("onResult", sid, fid, stateCode.ToAny(), headers.ToAny(), body.ToAny());
    }
}
internal static class HttpClientExtension
{
    public static void AddHeaders(this HttpClient client, string json)
    {
        Dictionary<string, string>? dict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
        if (dict is null) return;

        foreach (KeyValuePair<string, string> header in dict)
        {
            client.DefaultRequestHeaders.Add(header.Key, header.Value);
        }
    }

    public static string GetHeaders(this HttpResponseMessage rsp)
    {
        Dictionary<string, string> headersDict = new();
        foreach (KeyValuePair<string, IEnumerable<string>> header in rsp.Headers)
        {
            headersDict.Add(header.Key, string.Join(",", header.Value));
        }
        return JsonSerializer.Serialize(headersDict);
    }
}